import random
import re

from django_redis import get_redis_connection
from rest_framework import serializers
from rest_framework.serializers import raise_errors_on_nested_writes
from rest_framework.utils import model_meta

from answers.models import Question, Reply, Label
from celery_tasks.sms.tasks import ccp_send_sms_code
from articles.models import Article
from recruits.models import Enterprise, Recruit
from users.models import User


class UserSerizlizer(serializers.ModelSerializer):
    '''用户序列化器类'''
    sms_code = serializers.CharField(max_length=6,label='验证码',write_only=True)
    token = serializers.CharField(label='JWT Token',read_only=True)
    avatar = serializers.CharField(max_length=500,label="用户头像",default=None,read_only=True)

    class Meta:

        model = User
        fields = ('username','password','mobile','sms_code','token','avatar')

    def validate(self,attrs):

        username = attrs['username']
        sms_code = attrs['sms_code']
        password = attrs['password']
        mobile = attrs['mobile']

        if not re.match(r'^[a-zA-Z][a-zA-Z0-9]{5,14}$',username):
            raise serializers.ValidationError('用户名格式错误,请输入不能以数字开头,8-20位以字母数字组成的用户名')

        try:
            count = User.objects.filter(username=username).count()
        except Exception as e:
            raise serializers.ValidationError('查询数据库出错')
        if count > 0:
            raise serializers.ValidationError('该用户名已存在')

        if not re.match(r'^\d{6}$',sms_code):
            raise serializers.ValidationError('验证码输入不正确')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            raise serializers.ValidationError('手机号格式输入不正确')
        try:
            count = User.objects.filter(mobile=mobile).count()
        except Exception as e:
            raise serializers.ValidationError('查询数据库出错')
        if count > 0:
            raise serializers.ValidationError('该手机号已注册')
        # 4.password检验
        if not re.match(r'^[a-zA-Z0-9]{5,14}$', password):
            raise serializers.ValidationError('密码格式输入有误')
        # sms_code检验 (链接redis数据库)
        redis_conn = get_redis_connection('verify_code')

        # 从redis中取值
        sms_code_server = redis_conn.get('sms_%s' % mobile)
        # 判断该值是否存在
        if not sms_code_server:
            raise serializers.ValidationError('短信验证码已过期')
        if sms_code != sms_code_server.decode():
            raise serializers.ValidationError('短信验证码输入不正确')

        del attrs['sms_code']

        return attrs

    def create(self, validated_data):

        password = validated_data.get('password')
        del validated_data['password']
        user = super().create(validated_data)
        user.set_password(password)
        # 服务器生成jwt token, 保存当前用户的身份信息
        from rest_framework_jwt.settings import api_settings

        # 组织payload数据的方法
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        # 生成jwt token数据的方法
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        # 组织payload数据
        payload = jwt_payload_handler(user)
        # 生成jwt token
        token = jwt_encode_handler(payload)

        # 给user对象增加属性，保存jwt token的数据
        user.token = token
        user.save()

        return user


class SMSCodeSerializers(serializers.ModelSerializer):
    '''短信验证码序列化类'''
    mobile = serializers.CharField(label='手机号码',write_only=True)
    message = serializers.CharField(label='错误信息',default="短信验证码发送过于频繁")
    success = serializers.BooleanField(label='状态',default=False)
    sms_code = serializers.CharField(max_length=6,label='短信验证码',default='000000')

    class Meta:

        model = User

        fields = ('mobile','message','sms_code','success')

    def validate(self, attrs):

        mobile = attrs.get('mobile')

        # 将这句话提到前面最开始的位置:
        redis_conn = get_redis_connection('verify_code')
        # 进入函数后, 先获取存储在 redis 中的数据
        send_flag = redis_conn.get('send_flag_%s' % mobile)
        # 查看数据是否存在, 如果存在, 说明60s没过, 返回
        if send_flag:
            return attrs
        # 创建连接到redis的对象
        redis_conn = get_redis_connection('verify_code')

        # 7. 生成短信验证码：生成6位数验证码
        sms_code = '%06d' % random.randint(0, 999999)

        # 8. 保存短信验证码
        # 短信验证码有效期，单位：300秒
        pl = redis_conn.pipeline()
        pl.setex('sms_%s' % mobile, 60 * 10, sms_code)
        pl.setex('send_flag_%s' % mobile, 60, 1)
        pl.execute()

        # 发送短信验证码
        # 短信模板
        ccp_send_sms_code.delay(mobile, sms_code)

        attrs["success"] = True
        attrs["message"] = 'OK'
        attrs["sms_code"] = sms_code

        return attrs



class LoginViewSerializers(serializers.ModelSerializer):
    '''登录序列化器类'''
    token = serializers.CharField(label='JWT Token',read_only=True)

    class Meta:

        model = User

        fields = ('username','password','mobile','id','token','avatar')

        extra_kwargs = {
            'avatar':{"read_only":True},
            'username':{"required":False},
            'password':{"write_only":True}
        }


    def validate(self, attrs):

        mobile = attrs.get('username')
        password = attrs.get('password')

        if not all([mobile,password]):
            raise serializers.ValidationError('缺少比传参数')

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            raise serializers.ValidationError('手机号格式输入不正确')
        try:
            user = User.objects.get(mobile=mobile)
        except Exception as e:
            raise serializers.ValidationError('查询数据库出错')

        if not user.check_password(password):
            raise serializers.ValidationError('账号密码不匹配')

        from rest_framework_jwt.settings import api_settings

        # 组织payload数据的方法
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        # 生成jwt token数据的方法
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        # 组织payload数据
        payload = jwt_payload_handler(user)
        # 生成jwt token
        token = jwt_encode_handler(payload)

        attrs['username'] = user.username
        attrs['mobile'] = user.mobile
        attrs['token'] = token
        attrs['id'] = user.id
        attrs['avatar'] = user.avatar

        return attrs


class UserFansSerializer(serializers.ModelSerializer):

    class Meta:

        model = User

        fields = '__all__'
